#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 导入忽略Pydantic弃用警告的模块
import ignore_pydantic_warnings

import logging
import os
import sys
import warnings
import uvicorn
import json
from pathlib import Path
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from dotenv import load_dotenv

# 过滤掉 OBS 客户端的 SSL 警告
warnings.filterwarnings("ignore", category=DeprecationWarning, module="obs.client")

# 导入API路由
from api.routes import document, qa_generation
from api.routes.views import router as views_router
# 导入文件清理服务
from utils.file_cleaner import FileCleaner

# 全局变量存储文件清理服务
file_cleaner = None
# 日志初始化标记
_log_initialized = False
# 全局配置
_config = None
# 全局应用实例
_app = None

# 加载配置
def load_config():
    # 加载.env文件
    env_path = Path(".env")
    if not env_path.exists():
        print(f"配置文件不存在: {env_path}")
        sys.exit(1)
    
    load_dotenv(env_path)
    
    # 构建配置字典
    config = {
        "obs": {
            "access_key": os.getenv("OBS_ACCESS_KEY"),
            "secret_key": os.getenv("OBS_SECRET_KEY"),
            "endpoint": os.getenv("OBS_ENDPOINT"),
            "bucket": os.getenv("OBS_BUCKET"),
            "url_expire_seconds": int(os.getenv("OBS_URL_EXPIRE_SECONDS", "31536000")),
            "retry_times": int(os.getenv("OBS_RETRY_TIMES", "3")),
            "timeout": int(os.getenv("OBS_TIMEOUT", "60"))
        },
        "ai": {
            "api_key": os.getenv("AI_API_KEY"),
            "api_base": os.getenv("AI_API_BASE"),
            "model": os.getenv("AI_MODEL"),
            "temperature": float(os.getenv("AI_TEMPERATURE", "0.3")),
            "max_tokens": int(os.getenv("AI_MAX_TOKENS", "7000"))
        },
        "document": {
            "supported_formats": json.loads(os.getenv("DOCUMENT_SUPPORTED_FORMATS", '[".pdf", ".doc", ".docx"]')),
            "default_engine": os.getenv("DOCUMENT_DEFAULT_ENGINE", "markitdown"),
            "engines": json.loads(os.getenv("DOCUMENT_ENGINES", '["markitdown", "pdfminer"]')),
            "chunk_size": int(os.getenv("DOCUMENT_CHUNK_SIZE", "500")),
            "overlap_size": int(os.getenv("DOCUMENT_OVERLAP_SIZE", "50")),
            "performance": {
                "concurrent_pages": int(os.getenv("DOCUMENT_PERFORMANCE_CONCURRENT_PAGES", "4")),
                "max_workers": int(os.getenv("DOCUMENT_PERFORMANCE_MAX_WORKERS", "8")),
                "batch_size": int(os.getenv("DOCUMENT_PERFORMANCE_BATCH_SIZE", "10")),
                "enable_caching": os.getenv("DOCUMENT_PERFORMANCE_ENABLE_CACHING", "true").lower() == "true",
                "memory_limit": int(os.getenv("DOCUMENT_PERFORMANCE_MEMORY_LIMIT", "1024")),
                "timeout": int(os.getenv("DOCUMENT_PERFORMANCE_TIMEOUT", "300"))
            },
            "image": {
                "max_size": int(os.getenv("DOCUMENT_IMAGE_MAX_SIZE", "10485760")),
                "supported_formats": json.loads(os.getenv("DOCUMENT_IMAGE_SUPPORTED_FORMATS", '[".jpg", ".png", ".jpeg"]')),
                "quality": int(os.getenv("DOCUMENT_IMAGE_QUALITY", "85")),
                "min_size": int(os.getenv("DOCUMENT_IMAGE_MIN_SIZE", "1024")),
                "max_images_per_page": int(os.getenv("DOCUMENT_IMAGE_MAX_IMAGES_PER_PAGE", "10")),
                "enable_parallel_processing": os.getenv("DOCUMENT_IMAGE_ENABLE_PARALLEL_PROCESSING", "true").lower() == "true"
            }
        },
        "logging": {
            "level": os.getenv("LOGGING_LEVEL", "INFO"),
            "file": os.getenv("LOGGING_FILE", "logs/app.log"),
            "rotation": os.getenv("LOGGING_ROTATION", "500 MB")
        },
        "server": {
            "host": os.getenv("SERVER_HOST", "0.0.0.0"),
            "port": int(os.getenv("SERVER_PORT", "5000")),
            "workers": int(os.getenv("SERVER_WORKERS", "1")),
            "timeout": int(os.getenv("SERVER_TIMEOUT", "600")),
            "max_upload_size": int(os.getenv("SERVER_MAX_UPLOAD_SIZE", "104857600"))
        },
        "temp_files": {
            "cleanup_interval": int(os.getenv("TEMP_FILES_CLEANUP_INTERVAL", "3600")),
            "max_age": int(os.getenv("TEMP_FILES_MAX_AGE", "1800")),  # 默认30分钟(1800秒)
            "storage_path": os.getenv("TEMP_FILES_STORAGE_PATH", "uploads")
        },
        "storage": {
            "uploads_dir": os.getenv("STORAGE_UPLOADS_DIR", "uploads"),
            "output_dir": os.getenv("STORAGE_OUTPUT_DIR", "output"),
            "temp_dir": os.getenv("STORAGE_TEMP_DIR", "temp")
        },
        "image_handling": {
            "default": os.getenv("IMAGE_HANDLING_DEFAULT", "obs"),
            "options": json.loads(os.getenv("IMAGE_HANDLING_OPTIONS", '["obs", "local", "remove"]'))
        },
        "qa_generation": {
            "default_method": os.getenv("QA_GENERATION_DEFAULT_METHOD", "text_split"),
            "methods": json.loads(os.getenv("QA_GENERATION_METHODS", '["text_split", "ai_qa"]')),
            "default_chunk_size": int(os.getenv("QA_GENERATION_DEFAULT_CHUNK_SIZE", "500")),
            "default_overlap": int(os.getenv("QA_GENERATION_DEFAULT_OVERLAP", "50"))
        },
        "file_cleaner": {
            "max_age_minutes": int(os.getenv("FILE_CLEANER_MAX_AGE_MINUTES", "30")),
            "check_interval_seconds": int(os.getenv("FILE_CLEANER_CHECK_INTERVAL_SECONDS", "60"))
        }
    }
    
    return config

# 创建目录
def ensure_directories():
    dirs = ["uploads", "logs", "output", "temp"]
    for dir_name in dirs:
        os.makedirs(dir_name, exist_ok=True)

# 配置日志
def setup_logging(config):
    global _log_initialized
    # 如果已经初始化过，则跳过
    if _log_initialized:
        return
    
    import logging
    from logging.handlers import RotatingFileHandler
    import sys
    
    log_config = config["logging"]
    log_dir = os.path.dirname(log_config["file"])
    os.makedirs(log_dir, exist_ok=True)
    
    # 创建格式化器
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    
    # 文件处理器
    file_handler = RotatingFileHandler(
        log_config["file"],
        maxBytes=500 * 1024 * 1024,  # 默认500MB
        backupCount=5,
        encoding="utf-8"
    )
    file_handler.setFormatter(formatter)
    
    # 控制台处理器
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setFormatter(formatter)
    
    # 配置根日志记录器
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, log_config["level"]))
    
    # 清除现有的处理器
    root_logger.handlers.clear()
    
    # 添加处理器
    root_logger.addHandler(file_handler)
    root_logger.addHandler(console_handler)
    
    # 设置第三方库的日志级别
    logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
    logging.getLogger("uvicorn.error").setLevel(logging.WARNING)
    logging.getLogger("obs").setLevel(logging.WARNING)
    
    # 标记为已初始化
    _log_initialized = True
    
    # 输出初始日志
    root_logger.info("日志系统初始化完成")

# 定义生命周期管理器
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动前执行的代码
    logger = logging.getLogger(__name__)
    
    # 初始化文件清理服务
    global file_cleaner
    
    # 如果文件清理服务已经存在并在运行，则跳过
    if file_cleaner is not None and file_cleaner.running:
        yield
        return
    
    file_cleaner_config = app.state.config["file_cleaner"]
    storage_config = app.state.config["storage"]
    
    file_cleaner = FileCleaner(
        output_dir=storage_config["output_dir"],
        temp_dir=storage_config["temp_dir"],
        uploads_dir=storage_config["uploads_dir"],
        max_age_minutes=file_cleaner_config["max_age_minutes"],
        check_interval_seconds=file_cleaner_config["check_interval_seconds"]
    )
    
    # 将文件清理服务添加到应用状态中
    app.state.file_cleaner = file_cleaner
    
    # 启动文件清理服务
    await app.state.file_cleaner.start()
    logger.info(f"文件清理服务已启动，将清理超过 {file_cleaner_config['max_age_minutes']} 分钟的文件")
    
    # 生命周期的主体部分开始
    yield
    # 生命周期的主体部分结束
    
    # 关闭前执行的代码
    # 只有当服务正在运行时才关闭
    if file_cleaner is not None and file_cleaner.running:
        # 关闭文件清理服务
        await app.state.file_cleaner.stop()
        logger.info("文件清理服务已停止")

# 创建FastAPI应用
def create_app():
    global _app, _config
    
    # 如果应用已经创建，直接返回
    if _app is not None and _config is not None:
        return _app, _config
    
    _config = load_config()
    setup_logging(_config)
    ensure_directories()
    
    _app = FastAPI(
        title="文档转换知识片段工具",
        description="将PDF和Word文档转换为Markdown格式，并生成知识问答对",
        version="1.0.0",
        lifespan=lifespan
    )
    
    # 将配置添加到应用状态
    _app.state.config = _config
    
    # 配置CORS
    _app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    
    # 挂载静态文件
    _app.mount("/static", StaticFiles(directory="static"), name="static")
    
    # 注册路由
    _app.include_router(document.router)
    _app.include_router(qa_generation.router)
    _app.include_router(views_router)
    
    return _app, _config

app, config = create_app()

if __name__ == "__main__":
    server_config = config["server"]
    uvicorn.run(
        "main:app", 
        host=server_config["host"], 
        port=server_config["port"],
        workers=1,  # 减少worker数量，避免重复日志
        reload=False,  # 关闭热重载，避免多次初始化日志
        log_config=None,  # 禁用uvicorn默认日志配置
        access_log=False  # 禁用访问日志
    ) 